/*
 	SQLiteWrapper.h

 	Copyright (c) 2008 Bojan Rajkovic

 	Permission is hereby granted, free of charge, to any person obtaining a copy
 	of this software and associated documentation files (the "Software"), to deal
		in the Software without restriction, including without limitation the rights
 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 	copies of the Software, and to permit persons to whom the Software is
 	furnished to do so, subject to the following conditions:
	
 	The above copyright notice and this permission notice shall be included in
 	all copies or substantial portions of the Software.

 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 	THE SOFTWARE.
*/

/* This file will only be #include'd if we have SQLite3 (according to pkg-config) */

#ifndef _SQLITE_WRAPPER_H_
#define _SQLITE_WRAPPER_H_ 1

#define sqlite3_api
#include <sqlite3.h>
#include <vector>
#include "AllPurpose.h"
#include "Utility.h"

// define the E_DB_NOT_OPEN error
#define E_DB_NOT_OPEN -1

// define the exception that gets thrown when the database can't be opened
class SQLiteException : public std::exception {
	
		private:
			int error;	
			
		public:
			SQLiteException(int Error) {
				this->error = Error;
				Utility::LogMessage(Utility::FormatString("SQLiteException: %s", what()), M_ERROR);
			}
  		
  		virtual const char* what() const throw() {
				switch (error) {
					case E_DB_NOT_OPEN:
						return "Database not open.";
					case SQLITE_OK:
						return "Successful result";
					case SQLITE_ERROR:
						return "SQL error or missing database";
					case SQLITE_INTERNAL:
						return "An internal logic error in SQLite";
					case SQLITE_PERM:
						return "Access permission denied";
					case SQLITE_ABORT:
						return "Callback routine requested an abort";
					case SQLITE_BUSY:
						return "The database file is locked";
					case SQLITE_LOCKED:
						return "A table in the database is locked";
					case SQLITE_NOMEM:
						return "A malloc() failed";
					case SQLITE_READONLY:
					    return "Attempt to write a readonly database";
					case SQLITE_INTERRUPT:
						return "Operation terminated by sqlite_interrupt()";
					case SQLITE_IOERR:
						return "Some kind of disk I/O error occurred";
					case SQLITE_CORRUPT:
						return "The database disk image is malformed";
					case SQLITE_NOTFOUND:
						return "(Internal Only) Table or record not found";
					case SQLITE_FULL:
						return "Insertion failed because database is full";
					case SQLITE_CANTOPEN:
						return "Unable to open the database file";
					case SQLITE_PROTOCOL:
						return "Database lock protocol error";
					case SQLITE_EMPTY:
					    return "(Internal Only) Database table is empty";
					case SQLITE_SCHEMA:
					    return "The database schema changed";
					case SQLITE_TOOBIG:
					    return "Too much data for one row of a table";
					case SQLITE_CONSTRAINT:
						return "Abort due to contraint violation";
					case SQLITE_MISMATCH:
						return "Data type mismatch";
					case SQLITE_MISUSE:
					    return "Library used incorrectly";
					case SQLITE_NOLFS:
					    return "Uses OS features not supported on host";
					case SQLITE_AUTH:
					    return "Authorization denied";
					case SQLITE_ROW:
					    return "sqlite_step() has another row ready";
					case SQLITE_DONE:
					    return "sqlite_step() has finished executing";
					default:
						return Utility::FormatString("No clue what SQLite error %d is, check the documents.", error).c_str();
				}
  		}
};

// define the sqlite wrapper class
class SQLiteWrapper {

	// define private variables
	private:
		// the instance of the database that we'll be working with
		sqlite3 *database;
		// various message holders
	    char *errorMessage, **result;
	    // the database path
		std::string databasePath;
		// various numeric values
	    int retval, nrow, ncol;

	public:
	
		// the column names
		std::vector<std::string> columnHeaders;
		// the data
		std::vector<std::string> columnData;
	
		// constructor
	    SQLiteWrapper(std::string);
    	// executes the arbitrary sql statement
		int ExecuteSQL(std::string);
		// checks if a table exists
		int TableExists(std::string);
		// retrieves the last error from the database
		std::string GetLastError();

		// deconstructor
		~SQLiteWrapper();
};

#endif
